package nl.grol.yakshop.domain.service;

import java.util.logging.Logger;

import nl.grol.yakshop.domain.model.MilkableI;
import nl.grol.yakshop.domain.model.ShaveableI;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;

/**
 * @author mgrol
 *
 */
public class BruteForceProducionCalculator implements ProductionCalculatorI {
    @SuppressWarnings("unused")
	private static final Logger LOGGER = Logger.getLogger(BruteForceProducionCalculator.class.getName());

	public BruteForceProducionCalculator() {
	}
	
	@Override
	public double calculateYakMilkProductionForDay( MilkableI yak, int daysSinceStartOfShop ) {
		
		Preconditions.checkArgument(yak != null);
		Preconditions.checkArgument(daysSinceStartOfShop >= 0, 
				"calculateYakMilkProductionForDay daysSinceStartOfShop: received: %s expected: >= 0", daysSinceStartOfShop );

		/*
 		 * Note:
		 *  We delegate business-logic to the specific implementation of MilkableI:
		 * 	This allows other kinds of animals to have their own milk production algorithm
		 */
		return yak.getMilkProductionOnDay(daysSinceStartOfShop);
	}
	
	@Override
	public double calculateYakMilkProductionSofar( MilkableI yak, int daysSinceStartOfShop ) {
		double milkProductionSofarInLiters = 0.0;
		
		Preconditions.checkArgument(yak != null);
		Preconditions.checkArgument(daysSinceStartOfShop >= 0, 
				"calculateYakMilkProductionSofar daysSinceStartOfShop: received: %s expected: >= 0", daysSinceStartOfShop );

		/*
		 * For a single yak: Summarize milk production for all days since start of shop
		 */
		for( int dayOffset=0; dayOffset<daysSinceStartOfShop; dayOffset++ ) {
			milkProductionSofarInLiters += this.calculateYakMilkProductionForDay(yak, dayOffset);
		}

		return milkProductionSofarInLiters;
	}
	
	@Override
	public double calculateHerdMilkProductionSofar( ImmutableList<? extends MilkableI> herd, int daysSinceStartOfShop ) {
		double milkProductionSofarInLiters = 0;
		
		Preconditions.checkArgument(herd != null);
		Preconditions.checkArgument(daysSinceStartOfShop >= 0, 
				"calculateHerdMilkProductionSofar daysSinceStartOfShop: received: %s expected: >= 0", daysSinceStartOfShop );

		/*
		 * Summarize milk-production for all sheep in herd
		 */
		for( MilkableI yak : herd ) {
			milkProductionSofarInLiters += this.calculateYakMilkProductionSofar(yak, daysSinceStartOfShop);
		}
		
		return milkProductionSofarInLiters;
	}
	
	@Override
	public boolean mustYakBeShavedOnDay( ShaveableI yak, int daysSinceStartOfShop ) {

		Preconditions.checkArgument(yak != null);
		Preconditions.checkArgument(daysSinceStartOfShop >= 0, 
				"mustYakBeShavenOnDay daysSinceStartOfShop: received: %s expected: >= 0", daysSinceStartOfShop );
		
		/*
		 * Note:
		 *  We delegate business-logic to specific implementation of ShaveableI:
		 * 	This allows other kinds of animals to have their own shaving schedule
		 */
		boolean mustBeShavenOnday = yak.mustBeShavedOnDay(daysSinceStartOfShop);
		
//		log.info("Yak " + yak.getName() + " mustYakBeShavedOnDay at day " +  
//				daysSinceStartOfShop +  "=" + mustBeShavenOnday );

		return mustBeShavenOnday;
	}
	
	@Override
	public int calculateSkinsShavenFromYakSofar( ShaveableI yak, int daysSinceStartOfShop ) {
		int skinCount = 0;
		
		Preconditions.checkArgument(yak != null);
		Preconditions.checkArgument(daysSinceStartOfShop >= 0, 
				"calculateSkinsShavenForYakSofar daysSinceStartOfShop: received: %s expected: >= 0", daysSinceStartOfShop );

		/*
		 * For a single yak: Summarize all-shaving-actions for days since start of shop
		 */
		for( int dayOffset=0; dayOffset<daysSinceStartOfShop; dayOffset++ ) {
			boolean yakMustBeShaven = this.mustYakBeShavedOnDay(yak, dayOffset);
			if( yakMustBeShaven == true ) {
				skinCount++;
			}
		}
		
//		log.info("calculateSkinsShavenFromYakSofar at day " +  daysSinceStartOfShop + 
//				"=" + daysSinceStartOfShop );


		return skinCount;
	}
	
	@Override
	public int calculateHerdSkinProductionSofar( ImmutableList<? extends ShaveableI> herd, int daysSinceStartOfShop ) {
		int skinCount = 0;
		
		Preconditions.checkArgument(herd != null);
		Preconditions.checkArgument(daysSinceStartOfShop >= 0, 
				"calculateHerdSkinProductionSofar daysSinceStartOfShop: received: %s expected: >= 0", daysSinceStartOfShop );

		/*
		 * Summarize shaving-actions or all sheep in herd
		 */
		for( ShaveableI yak : herd ) {
			skinCount += this.calculateSkinsShavenFromYakSofar(yak, daysSinceStartOfShop);
		}
		
//		log.info("calculateHerdSkinProductionSofar at day " +  daysSinceStartOfShop + 
//				"=" + daysSinceStartOfShop );

		return skinCount;
	}

}
